using System;
using System.Configuration;
using System.Collections.Generic;
using System.Windows.Forms;
using MIMPWinForms.Forms;
using MIMPWinForms.MIMPGameServices;
using MIMPGameLibrary;
using System.IO;

namespace MIMPWinForms
{
    public class MIMPApplicationContext : ApplicationContext
    {
        private static readonly log4net.ILog log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);
        ServiceProvider gameServices;
        MainForm main;
        MainMenuForm menu;
        GameState gs;

        public MIMPApplicationContext() {
            LoadLogger();
            if (log.IsDebugEnabled) log.Debug("Logger created");
            gameServices = new ServiceProvider();

            menu = new MainMenuForm();

            if (log.IsDebugEnabled) log.Debug("Hooking up menu form handlers");
            menu.LoadGame += new EventHandler<EventArgs<GameState>>(menu_LoadGame);
            menu.ExitGame += new System.ComponentModel.CancelEventHandler(ExitGame);
            menu.Closing += new System.ComponentModel.CancelEventHandler(menu_Closing);
            menu.Closed += new EventHandler(menu_Closed);

            if (log.IsDebugEnabled) log.Debug("Showing the main menu.");
            menu.Show();
        }

        private void LoadLogger() {
            string configname = ConfigurationManager.AppSettings["log4net"];
            if (File.Exists(configname)) {
                log4net.Config.XmlConfigurator.Configure(new FileInfo(configname));
            }
        }

        void menu_Closing(object sender, System.ComponentModel.CancelEventArgs e) {
            if (log.IsInfoEnabled) log.Debug("Entered menu_Closing");
            if (main != null) {
                e.Cancel = true;
                menu.Hide();
            }
            if (log.IsInfoEnabled) log.Debug("Exiting menu_Closing");
        }

        /// <summary>
        /// If the Main Menu has closed and the main screen has not been loaded yet, exit the application.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        void menu_Closed(object sender, EventArgs e) {
            if (log.IsInfoEnabled) log.Debug("Entered menu_Closed");
            if (main == null) {
                ExitThread();
            }
            if (log.IsInfoEnabled) log.Debug("Exiting menu_Closed");
        }

        void ExitGame(object sender, System.ComponentModel.CancelEventArgs e) {
            if (log.IsInfoEnabled) log.Debug("Entered ExitGame");
            if (ConfirmExit() == DialogResult.OK) {
                if (log.IsInfoEnabled) log.Info("Exiting thread.");
                ExitThread();
            } else {
                if (log.IsDebugEnabled) log.Debug("User canceled exit game event.");
                e.Cancel = true;
            }
            if (log.IsInfoEnabled) log.Debug("Exiting ExitGame");
        }

        DialogResult ConfirmExit() {
            return MessageBox.Show("Are you sure you want to exit the game?", "Exit MIMP",
                MessageBoxButtons.OKCancel, MessageBoxIcon.None);
        }

        void menu_LoadGame(object sender, EventArgs<GameState> e) {
            if (log.IsInfoEnabled) log.Debug("Entered menu_LoadGame");
            
            gs = e.EventData;

            LocalGameStateController gsController = new LocalGameStateController(gs);
            main = new MainForm();
            if (log.IsDebugEnabled) log.Debug("Adding services.");
            gameServices.AddService<IControlPanelEventsService>(main);
            gameServices.AddService<IGameStateEventsService>(gsController);
            gameServices.AddService<IGameScreenEventsService>(main.GameScreen);

            main.SetServices(gameServices);
            main.GameScreen.SetServices(gameServices);
            gsController.SetService(gameServices);

            if (log.IsDebugEnabled) log.Debug("Hooking up main form events.");
            main.Closing += new System.ComponentModel.CancelEventHandler(ExitGame);
            main.MainMenuButtonClicked += new EventHandler(main_MainMenuButtonClicked);

            menu.IsGameInProgress = true;
            menu.Hide();

            if (log.IsDebugEnabled) log.Debug("Starting the game.");
            gsController.StartGame();
            if (log.IsDebugEnabled) log.Debug("Showing the main form.");
            main.Show();
            if (log.IsInfoEnabled) log.Debug("Exiting menu_LoadGame");
        }

        void main_MainMenuButtonClicked(object sender, EventArgs e) {
            if (log.IsInfoEnabled) log.Info("Entered main_MainMenuButtonClicked");
            menu.ShowDialog(main);
            if (log.IsInfoEnabled) log.Info("Exiting main_MainMenuButtonClicked");
        }
    }

    static class Program
    {
        /// <summary>
        /// The main entry point for the application.
        /// </summary>
        [STAThread]
        static void Main() {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new MIMPApplicationContext());
        }
    }
}

